package com.skillworld.webapp.model.enrollment;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;

import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;

import com.skillworld.webapp.model.course.Course;
import com.skillworld.webapp.model.enrollment.ReleasedExam.Grade;
import com.skillworld.webapp.model.lesson.Lesson;
import com.skillworld.webapp.model.user.User;

@Entity
@Table(name="Enrollment")
public class Enrollment
{
	private Long enrollmentId;
    private Course course;
	private User student;
	private Calendar enrollmentDate;
	private Calendar finishDate;
	private List<Examination> examinations;

	
	protected Enrollment()
	{

	}

	public Enrollment(Course course, User student)
    {
		this.course = course;
		this.student = student;
		this.enrollmentDate = Calendar.getInstance();
		this.finishDate = null;
		
		this.examinations = new ArrayList<Examination>();
		for (Lesson lesson : course.getLessons())
		{ this.examinations.add(new Examination(this, lesson)); }
	}

	
	@SequenceGenerator(name="EnrollmentIdGenerator",sequenceName="EnrollmentSeq")
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO,generator="EnrollmentIdGenerator")
    @Column(name="idEnrollment")
	public Long getEnrollmentId()
	{
        return enrollmentId;
    }
	
	protected void setEnrollmentId(Long enrollmentId)
	{
        this.enrollmentId = enrollmentId;
    }
	
	@ManyToOne(optional=false,fetch=FetchType.LAZY)
    @JoinColumn(name="idCourse")
	public Course getCourse()
	{
        return course;
    }
	
	protected void setCourse(Course course)
	{
        this.course = course;
    }
	
    @ManyToOne(optional=false,fetch=FetchType.LAZY)
    @JoinColumn(name="idUser")
    public User getStudent()
    {
        return student;
    }
    
    protected void setStudent(User student)
    {
        this.student = student;
    }
	
	@Temporal(TemporalType.TIMESTAMP)
	@Column(name="enrollmentDate")
	public Calendar getEnrollmentDate()
	{
        return enrollmentDate;
    }

    protected void setEnrollmentDate(Calendar enrollmentDate)
    {
        this.enrollmentDate = enrollmentDate;
    }

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name="finishDate")
	public Calendar getFinishDate()
    {
        return finishDate;
    }
    
	public void setFinishDate(Calendar finishDate)
	{
        this.finishDate = finishDate;
    }
	
	@Transient
	public boolean isFinished()
	{
	    return getCompleted().size() == getExaminations().size();
	}

	@OneToMany(mappedBy="enrollment",fetch=FetchType.LAZY)
	@Cascade({CascadeType.SAVE_UPDATE,CascadeType.DELETE})
	@OrderBy
    public List<Examination> getExaminations() 
    {
        return examinations;
    }

    protected void setExaminations(List<Examination> studentLessons)
    {
        this.examinations = studentLessons;
    }
    
    @Transient
    public List<Examination> getCompleted()
    {
        List<Examination> completed = new ArrayList<Examination>();
        for (Examination ex : getExaminations())
        { 
            if (ex.isFinished())
            { completed.add(ex); }
        }
        
        return completed;
    }
    
    public void evaluate(Examination examination, 
                            Grade grade, String commentary)
    {
        examination.evaluate(grade, commentary);
        if (this.isFinished())
        { finishDate = examination.getFinishDate(); }
    }
}
